# 导入Anthropic库，用于与Claude API进行交互
from anthropic import Anthropic
# 导入load_dotenv函数，用于从.env文件加载环境变量（如API密钥）
from dotenv import load_dotenv
# 导入format_user_message函数，用于将数据字典格式化为结构化的用户消息
from app.utils.format_message import format_user_message

# 加载.env文件中的环境变量，这样可以安全地存储和访问API密钥
load_dotenv()


# 定义Claude服务类，封装与Claude AI模型交互的所有功能
class ClaudeService:
    # 初始化方法，创建一个默认的Anthropic客户端实例
    def __init__(self):
        # 创建默认客户端，它会自动从环境变量中获取API密钥
        self.default_client = Anthropic()

    # 定义调用Claude API的方法
    def call_claude_api(
        self, system_prompt: str, data: dict, api_key: str | None = None
    ) -> str:
        """
        向Claude发起API调用并返回响应。

        参数:
            system_prompt (str): 指令/系统提示
            data (dict): 用于格式化用户消息的变量字典
            api_key (str | None): 可选的自定义API密钥

        返回:
            str: Claude的响应文本
        """
        # 使用format_user_message函数将数据字典转换为结构化的用户消息
        # 这个函数会将不同类型的数据用XML风格的标签包装起来
        user_message = format_user_message(data)

        # 如果提供了自定义API密钥，则创建一个新的客户端实例使用该密钥
        # 否则使用初始化时创建的默认客户端
        client = Anthropic(api_key=api_key) if api_key else self.default_client

        # 调用Anthropic API创建消息
        # model参数指定使用的Claude模型版本
        # max_tokens参数限制响应的最大令牌数
        # temperature参数控制响应的随机性（0表示最确定性的响应）
        # system参数提供系统指令
        # messages参数包含用户消息
        message = client.messages.create(
            model="claude-3-5-sonnet-latest",  # 使用Claude 3.5 Sonnet最新版本
            max_tokens=4096,  # 限制响应最多包含4096个令牌
            temperature=0,  # 设置温度为0，生成最确定性的响应
            system=system_prompt,  # 传入系统提示
            messages=[
                # 创建用户角色的消息，包含格式化后的文本内容
                {"role": "user", "content": [{"type": "text", "text": user_message}]}
            ],
        )
        # 返回响应中的第一个内容块的文本
        # type: ignore注释用于忽略类型检查器的警告
        return message.content[0].text  # type: ignore

    # 定义计算令牌数量的方法
    def count_tokens(self, prompt: str) -> int:
        """
        计算提示中的令牌数量。

        参数:
            prompt (str): 要计算令牌数量的提示

        返回:
            int: 输入令牌数量
        """
        # 使用默认客户端的count_tokens方法计算给定提示的令牌数
        # 这对于估计API调用的成本和确保不超过模型的最大令牌限制很有用
        response = self.default_client.messages.count_tokens(
            model="claude-3-5-sonnet-latest",  # 使用与API调用相同的模型
            messages=[{"role": "user", "content": prompt}],  # 创建用户角色的消息
        )
        # 返回输入令牌的数量
        return response.input_tokens
